﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace iOak.Common
{
    public static class CreateDynamicClass
    {
        public static Type CreateClass(List<string> nameList)
        {
            // 定义程序集名称
            AssemblyName aName = new AssemblyName("DynamicClassAssembly");
            AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);

            // 创建模板
            ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);

            // 创建class
            TypeBuilder tb = mb.DefineType("DynamicClass", TypeAttributes.Public);

            nameList.AsParallel().ForAll(name =>
            {
                // 定义属性
                PropertyBuilder pbNumber = tb.DefineProperty(name, PropertyAttributes.HasDefault, typeof(string), null);
                
                // 定义访问权限
                MethodAttributes getSetAttr = MethodAttributes.Public;

                // 定义私有字段
                FieldBuilder fbNumber = tb.DefineField(name.ToLower(), typeof(string), FieldAttributes.Private);

                // 定义get方法
                MethodBuilder mbNumberGetAccessor = tb.DefineMethod("get_" + name, getSetAttr, typeof(string), Type.EmptyTypes);

                // 注入方法块
                ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator();
                numberGetIL.Emit(OpCodes.Ldarg_0);
                numberGetIL.Emit(OpCodes.Ldfld, fbNumber);
                numberGetIL.Emit(OpCodes.Ret);

                // 定义set方法
                MethodBuilder mbNumberSetAccessor = tb.DefineMethod("set_" + name, getSetAttr, null, new Type[] { typeof(string) });

                // 注入方法块
                ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator();
                numberSetIL.Emit(OpCodes.Ldarg_0);
                numberSetIL.Emit(OpCodes.Ldarg_1);
                numberSetIL.Emit(OpCodes.Stfld, fbNumber);
                numberSetIL.Emit(OpCodes.Ret);

                // 添加到属性
                pbNumber.SetGetMethod(mbNumberGetAccessor);
                pbNumber.SetSetMethod(mbNumberSetAccessor);
            });

            // 返回新类型
            return tb.CreateType();
        }
    }
}
